package com.ruoyi.system.chat.netty;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.system.domain.dto.ChartData;
import com.ruoyi.system.domain.dto.WebSocketConnectDTO;
import com.ruoyi.system.service.IChatMessagesService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;

/**
 * WebSocket消息处理器
 */
@Component
@ChannelHandler.Sharable
public class WebSocketChannelHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Autowired
    private IChatMessagesService chatMessagesService;

    // AttributeKeys
    private static final AttributeKey<Long> CLUB_ID_KEY = AttributeKey.valueOf("clubId");
    private static final AttributeKey<Long> USER_ID_KEY = AttributeKey.valueOf("userId");
    private static final AttributeKey<String> NICKNAME_KEY = AttributeKey.valueOf("nickName");
    private static final AttributeKey<String> AVATAR_KEY = AttributeKey.valueOf("avatar");

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("=== Channel active: " + ctx.channel().id() + " ===");
        System.out.println("Remote address: " + ctx.channel().remoteAddress());
        System.out.println("Local address: " + ctx.channel().localAddress());
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("=== Channel inactive: " + ctx.channel().id() + " ===");
        Long clubId = ctx.channel().attr(CLUB_ID_KEY).get();
        if (clubId != null) {
            GroupChatManager.removeChannel(clubId, ctx.channel());
            System.out.println("User removed from group: clubId=" + clubId);
        }
        super.channelInactive(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        System.out.println("=== User event triggered: " + evt.getClass().getSimpleName() + " ===");
        // 发送连接成功消息
        String welcomeMsg = "{\"type\":\"welcome\",\"message\":\"Connected successfully\"}";
        ctx.channel().writeAndFlush(new TextWebSocketFrame(welcomeMsg));
        super.userEventTriggered(ctx, evt);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
        String data = frame.text();
        System.out.println("=== Received TextWebSocketFrame: " + data + " ===");
        if (!JSONUtil.isJson(data)) {
            String errorResp = "{\"type\":\"error\",\"message\":\"Invalid JSON format\"}";
            ctx.channel().writeAndFlush(new TextWebSocketFrame(errorResp));
            return;
        }
        WebSocketConnectDTO bean = JSONUtil.toBean(data, WebSocketConnectDTO.class);
        if (ObjectUtil.isNotEmpty(bean.getClubId())) {
            ctx.channel().attr(CLUB_ID_KEY).set(bean.getClubId());
            ctx.channel().attr(USER_ID_KEY).set(bean.getUserId());
            ctx.channel().attr(NICKNAME_KEY).set(bean.getNickname());
            ctx.channel().attr(AVATAR_KEY).set(bean.getAvatar());
            // 添加到群聊组
            GroupChatManager.addChannel(bean.getClubId(), ctx.channel());
            // 发送连接成功消息
            String welcomeMsg = "{\"type\":\"welcome\",\"message\":\"Connected successfully\",\"clubId\":" + bean.getUserId() + ",\"userId\":" + bean.getUserId() + "}";
            ctx.channel().writeAndFlush(new TextWebSocketFrame(welcomeMsg));
            System.out.println("Welcome message sent to client");
            return;
        }


        try {
            Long clubId = ctx.channel().attr(CLUB_ID_KEY).get();
            Long userId = ctx.channel().attr(USER_ID_KEY).get();
            String nickName = ctx.channel().attr(NICKNAME_KEY).get();
            String avatar = ctx.channel().attr(AVATAR_KEY).get();
            System.out.println("Channel attributes: clubId=" + clubId + ", userId=" + userId + ", nickName=" + nickName);
            // 如果用户信息还没有设置，发送错误消息
            if (clubId == null || userId == null) {
                System.out.println("User info not found in channel attributes");
                String errorResp = "{\"type\":\"error\",\"message\":\"User info not set. Please reconnect with proper parameters.\"}";
                ctx.channel().writeAndFlush(new TextWebSocketFrame(errorResp));
                return;
            }
            String text = frame.text();
            System.out.println("Received WebSocket message: " + text);
            // 解析JSON消息
            try {
                ChartData chartData = JSONUtil.toBean(text, ChartData.class);
                if (chartData != null && !chartData.getContent().isEmpty()) {
                    // 发送回客户端确认
                    String resp = "{\"type\":\"message\",\"content\":\"" + chartData.getContent() + "\",\"userId\":" + userId + ",\"nickName\":\"" + nickName + "\",\"avatar\":\"" + avatar + "\",\"createdAt\":\"" + new Date() + "\"}";
                    GroupChatManager.broadcast(clubId, resp);
                    System.out.println("Message echo sent back to client");
                } else {
                    String errorResp = "{\"type\":\"error\",\"message\":\"Message content is empty\"}";
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(errorResp));
                }
            } catch (Exception e) {
                System.err.println("Failed to parse JSON message: " + e.getMessage());
                String errorResp = "{\"type\":\"error\",\"message\":\"Invalid JSON format\"}";
                ctx.channel().writeAndFlush(new TextWebSocketFrame(errorResp));
            }

        } catch (Exception e) {
            System.err.println("Error handling WebSocket frame: " + e.getMessage());
            e.printStackTrace();
            String errorResp = "{\"type\":\"error\",\"message\":\"Internal server error\"}";
            ctx.channel().writeAndFlush(new TextWebSocketFrame(errorResp));
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("=== Handler removed: " + ctx.channel().id() + " ===");
        Long clubId = ctx.channel().attr(CLUB_ID_KEY).get();
        if (clubId != null) {
            GroupChatManager.removeChannel(clubId, ctx.channel());
        }
        super.handlerRemoved(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println("=== WebSocket exception: " + cause.getMessage() + " ===");
        System.err.println("Exception type: " + cause.getClass().getSimpleName());
        cause.printStackTrace();

        // 不要立即关闭连接，除非是IO异常
        if (cause instanceof java.io.IOException) {
            System.err.println("IO Exception detected, closing channel");
            ctx.close();
        } else {
            System.err.println("Non-IO exception, keeping channel open");
        }
    }
}

// QueryStringDecoder工具
class QueryStringDecoder {
    public static Map<String, String> decodeParams(String uri) {
        java.util.HashMap<String, String> map = new java.util.HashMap<>();
        int idx = uri.indexOf('?');
        if (idx == -1) return map;
        String[] params = uri.substring(idx + 1).split("&");
        for (String param : params) {
            String[] kv = param.split("=", 2);
            if (kv.length == 2) {
                try {
                    map.put(kv[0], java.net.URLDecoder.decode(kv[1], "UTF-8"));
                } catch (Exception e) {
                    System.err.println("Failed to decode param: " + kv[0] + "=" + kv[1]);
                    map.put(kv[0], kv[1]);
                }
            }
        }
        return map;
    }
} 